package com.saturday.feign;

import cn.hutool.core.codec.Base64;
import com.saturday.common.constants.CommonConsts;
import com.saturday.common.constants.ResultConsts;
import com.saturday.common.exception.BusinessException;
import com.saturday.common.exception.UserContextLoseException;
import feign.*;
import feign.httpclient.ApacheHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;

import java.io.IOException;
import java.util.Collection;
import java.util.List;

import static com.saturday.common.constants.CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_CODE_KEY;
import static com.saturday.common.constants.CommonConsts.FEIGN_RESPONSE_HEADER_ERROR_MESSAGE_KEY;

@Slf4j
public class FeignExceptionClient implements Client {

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        Response response = new ApacheHttpClient().execute(request, options);

        RequestTemplate requestTemplate = response.request().requestTemplate();
        Target<?> target = requestTemplate.feignTarget();

        String serviceName = target.name();
        Class<?> type = target.type();
        String api = type.getName();
        String url = requestTemplate.url();

        Collection<String> errorCodes = response.headers().get(FEIGN_RESPONSE_HEADER_ERROR_CODE_KEY);
        Collection<String> errormessage = response.headers().get(FEIGN_RESPONSE_HEADER_ERROR_MESSAGE_KEY);
        String errorMessage = null;
        if (null != errormessage && !errormessage.isEmpty()) {
            errorMessage = (String) ((List) errormessage).get(0);
            errorMessage = Base64.decodeStr(errorMessage, CommonConsts.UTF8);
        }

        if (CollectionUtils.isNotEmpty(errorCodes)) {
            logInvokeError(serviceName, api, url);

            Object errorCode = ((List) errorCodes).get(0);
            if (ResultConsts.NOT_LOGIN.toString().equals(errorCode)) {
                throw UserContextLoseException.createException();
            }

            if (String.valueOf(HttpStatus.EXPECTATION_FAILED.value()).equals(errorCode)) {
                throw BusinessException.createException("系统异常");
            }

            if (String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()).equals(errorCode)) {
                throw BusinessException.createException("系统异常");
            }

            if (StringUtils.isNotEmpty(errorMessage)) {
                throw BusinessException.createException(errorMessage);
            }
            throw BusinessException.createException("系统异常");
        }

        if (StringUtils.isNotEmpty(errorMessage)) {
            logInvokeError(serviceName, api, url);
            throw BusinessException.createException(errorMessage);
        }

        return response;
    }

    private void logInvokeError(String serviceName, String api, String method) {
        log.error("调用微服务[{}]-Api[{}]-Uri[{}]异常", serviceName, api, method);
    }
}
